/*
 * Copyright (c) 2008 Anshuman Manur <anshuman.manur@gmail.com>,
 * Lavanya Shastri <lavanya.shastri@gmail.com>
 * 
 * This file is part of Andronova.
 * 
 * Andronova is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 * 
 * Andronova is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *  
 * You should have received a copy of the GNU General Public License
 * along with Andronova.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * This file may use the functionality provided by the library
 * jid3lib version 0.5.4 (<http://sourceforge.net/projects/javamusictag/>).
 * jid3lib and its uses are covered by GNU Lesser General Public License.
 * 
 */

package com.googlecode.andronova;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Stack;

import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.DialogInterface.OnCancelListener;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.os.Handler;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.View;
import android.view.Menu.Item;
import android.view.View.OnKeyListener;
import android.widget.ArrayAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.Toast;

import com.googlecode.andronova.helper.DBConstants;
import com.googlecode.andronova.helper.Library;
import com.googlecode.andronova.helper.PlayBackOrganiser;
import com.googlecode.andronova.helper.PlayList;
import com.googlecode.andronova.helper.Song;

public class LibraryActivity extends ListActivity {
	
	private int listMode = MODE_MAIN;
	
	private static final int MODE_MAIN = 0;
	private static final int MODE_ARTIST = 1;
	private static final int MODE_ALBUM = 2;
	private static final int MODE_SONG = 3;
	private static final int MODE_GENRE = 4;
	
	private static final String TITLE_MAIN = "Library";
	private static final String TITLE_ARTIST = "Artist";
	private static final String TITLE_ALBUM = "Album";
	private static final String TITLE_GENRE = "Genre";
	private static final String TITLE_SONG = "Song";
	
	private static final String MITEM_NAME_CONFIGURE = "Configure";
	private static final String MITEM_NAME_PLAYLIST = "Playlist";
	private static final String MITEM_NAME_DONE = "Exit";
	private static final String MITEM_NAME_TAGEDITOR = "Tag Editor";
	private static final String MITEM_NAME_HELP = "Help";
	private static final String MITEM_NAME_SETPATH = "Set Path";
	
	private static final int MITEM_ID_CONFIGURE = 0;
	private static final int MITEM_ID_PLAYLIST = 1;
	private static final int MITEM_ID_DONE = 2;
	private static final int MITEM_ID_TAGEDITOR = 3;
	private static final int MITEM_ID_HELP = 4;
	private static final int MITEM_ID_SETPATH = 5;
	
	private static final int M_GID_REGULAR = 1;
	private static final int M_GID_SONG = 2;
	private static final int M_GID_MAIN = 3;
	
	private boolean addMode = false;
	/*
	 * addMode signals either PlayList Add Mode or "Normal" library mode
	 */
	
	private boolean isConfigured = false;
	
	private	static final String[] ITEMS_MAIN = { "All", "Artist", "Album", "Genre", "Playlist" };
	
	private String selection1 = "";
	private String selection2 = "";
	
	private Library library;
	private PlayList playList;
	
	private Cursor c;
	
	private ListActivity ctx;
	
	private ListAdapter adapter;
	
	private Stack<Cursor> cursorStack = new Stack<Cursor>();	
	private Stack<Integer> positionStack = new Stack<Integer>();
	private Stack<String> titleStack = new Stack<String>();
	
	private Handler myHandler;
	private ProgressDialog pDialog;
	
	@Override
	protected void onCreate(Bundle icicle) {
		super.onCreate(icicle);
		setTitle("Library");
			
		adapter = getAdapter();
		setListAdapter(adapter);
		setSelection(0);
		
		ctx = this;
		myHandler = new Handler();
		
		this.getListView().setOnKeyListener(new OnKeyListener() {
			
			public boolean onKey(View v, int keyCode, KeyEvent keyEvent) {
		
				if(keyEvent.getAction() != KeyEvent.ACTION_UP)
					return false;
				
				if(keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
			
					if(listMode == MODE_MAIN)
						return true;
				
					if(listMode==MODE_ARTIST || listMode==MODE_GENRE || ((listMode==MODE_ALBUM || listMode==MODE_SONG) && cursorStack.empty())) {
						adapter = new ArrayAdapter<String>(ctx, R.layout.row, ITEMS_MAIN);
						setListAdapter(adapter);
						setTitle(TITLE_MAIN);
					
						if(listMode == MODE_SONG)
							setSelection(0);
						
						else if(listMode == MODE_ARTIST)
							setSelection(1);
						
						else if(listMode == MODE_ALBUM) 
							setSelection(2);
						
						else 
							setSelection(3);
						
						listMode = MODE_MAIN;						
						return true;
					}
					
					if(listMode == MODE_ALBUM) {
						listMode = MODE_ARTIST;
						c = cursorStack.pop();
						SimpleCursorAdapter sCA = (SimpleCursorAdapter) adapter;
						sCA.changeCursor(c);
						setListAdapter(adapter);
						setSelection(positionStack.pop().intValue());
						setTitle(TITLE_ARTIST);
						return true;
					}
					
					if(listMode == MODE_SONG) {
						c = cursorStack.pop();
						String[] s = c.getColumnNames();
					
						if(s[1].equals(DBConstants.CNAME_GENRE)) {
							listMode = MODE_GENRE;
							selection1 = "";
							setTitle(TITLE_GENRE);
						}
						
						else {
							listMode = MODE_ALBUM;
							if(selection2 == "")
								selection1 = "";
							else
								selection2 = "";
							setTitle(titleStack.pop());
						}						
						
						SimpleCursorAdapter sCA = (SimpleCursorAdapter) adapter;
						sCA.changeCursor(c);
						setListAdapter(adapter);
						setSelection(positionStack.pop().intValue());
						return true;
					}
				}
				return false;
			}
		});
		
		SQLiteDatabase db;
		try {
			db = this.openDatabase(DBConstants.DB_NAME, null);		
		}
		catch(FileNotFoundException e) {
			try {
				db = this.createDatabase(DBConstants.DB_NAME, DBConstants.DB_VERSION, MODE_PRIVATE, null);
				db.execSQL(DBConstants.LIB_TABLE_CREATE);
				db.execSQL(DBConstants.PLED_TABLE_CREATE);
				this.showAlert(PlayScreen.WARNING, android.R.id.icon, "Configure Your library before operating on it", "OK", false);
			}
			catch(FileNotFoundException Fe) {
				this.showAlert(PlayScreen.ERROR, android.R.id.icon, "Unable to create database", "OK", false);
				return;
			}
		}
		
		Intent i = getIntent();
		addMode = i.getBooleanExtra("" + R.string.MODE, false);
		
		if(addMode)
			playList = new PlayList(db);
		library = new Library(db);		
		
		if(library.getSize() != 0)
			isConfigured = true;
	}
		

	@Override
	protected void onResume() {
		super.onResume();
		
		if(c != null)
			c.requery();
	}

	
/*	@Override
	protected void onPause() {
		super.onPause();
		
		library = null;
		playList = null;
	}
*/


	@Override
	protected void onListItemClick(ListView l, View v, int position, long id) {
		super.onListItemClick(l, v, position, id);
		
		if(!isConfigured) {
			Toast toast = Toast.makeText(this, "Library Not Configured", Toast.LENGTH_SHORT);
			toast.show();
			return;
		}
		
		switch(listMode) {
		case MODE_MAIN:
			switch(position) {
			case 0:
				listMode = MODE_SONG;
				adapter = getAdapter();
				setListAdapter(adapter);
				setTitle(TITLE_SONG);
				break;
			
			case 1:
				listMode = MODE_ARTIST;
				adapter = getAdapter();
				setListAdapter(adapter);
				setTitle(TITLE_ARTIST);
				break;
				
			case 2:
				listMode = MODE_ALBUM;
				adapter = getAdapter();
				setListAdapter(adapter);
				setTitle(TITLE_ALBUM);
				break;
				
			case 3:
				listMode = MODE_GENRE;
				adapter = getAdapter();
				setListAdapter(adapter);
				setTitle(TITLE_GENRE);
				break;
				
			case 4:
				Intent i = new Intent(this, PlaylistEditor.class);
				startActivity(i);
				finish();
				break;
			}
			break;
		
		case MODE_ARTIST:
			listMode = MODE_ALBUM;
			TextView tvA = (TextView) v;
			String artist = tvA.getText().toString();			
			selection1 = DBConstants.CNAME_ARTIST + "=\'" + artist + "\'";
			cursorStack.push(c);
			positionStack.push(new Integer(position));
			c = library.getCursor(selection1, DBConstants.CNAME_ALBUM);
			SimpleCursorAdapter sCA = (SimpleCursorAdapter) adapter;
			sCA.changeCursor(c);
			setSelection(0);
			setTitle(artist);
			break;
		
		case MODE_ALBUM:
			listMode = MODE_SONG;
			TextView tvAl = (TextView) v;
			String album = tvAl.getText().toString();
			if(selection1 == "")
				selection1 = DBConstants.CNAME_ALBUM + "=\'" + album + "\'";
			else 
				selection2 = DBConstants.CNAME_ALBUM + "=\'" + album + "\'";
			cursorStack.push(c);
			positionStack.push(new Integer(position));
			c = library.getCursor(((selection2=="")? selection1 : selection1 + " and " + selection2), DBConstants.CNAME_TITLE);
			SimpleCursorAdapter sCB = (SimpleCursorAdapter) adapter;
			sCB.changeCursor(c);
			setSelection(0);
			titleStack.push((String)getTitle());
			setTitle(album);
			break;
		
		case MODE_GENRE:
			listMode = MODE_SONG;
			TextView tvG = (TextView) v;
			String genre = tvG.getText().toString();
			selection1 = DBConstants.CNAME_GENRE + "=\'" + genre + "\'";
			cursorStack.push(c);
			c = library.getCursor(selection1, DBConstants.CNAME_TITLE);
			positionStack.push(new Integer(position));
			SimpleCursorAdapter sCC = (SimpleCursorAdapter) adapter;
			sCC.changeCursor(c);
			setSelection(0);
			setTitle(genre);
			break;
			
		case MODE_SONG:
			try {
				Song s = library.getSong(id);
				if(addMode) {
					if(playList.add(s) == -1)
						this.showAlert(PlayScreen.ERROR, android.R.id.icon, "Unable to add this song to Playlist", "OK", false);
				}
				else {		
					if(Playback.pbOrganiser==null || !Playback.pbOrganiser.isLibraryMode())
						Playback.pbOrganiser = new PlayBackOrganiser(library);
					Playback.pbOrganiser.setCurrentSong(s);
					this.setResult(RESULT_OK);
					this.finish();
				}
			}
			catch(IOException e) {
				this.showAlert(PlayScreen.ERROR, android.R.id.icon, "Unable to read song" + "\n" + e.toString(), "OK", false);
			}			
			break;
		}
	}
	

	private ListAdapter getAdapter() {
		switch(listMode) {
		case MODE_MAIN:
			return new ArrayAdapter<String>(this, R.layout.row, ITEMS_MAIN);
			
		case MODE_ARTIST:
			c = library.getCursor(null,  DBConstants.CNAME_ARTIST);
			return new SimpleCursorAdapter(this, R.layout.row, c, new String[] { DBConstants.CNAME_ARTIST }, new int[] { R.id.row });
			
		case MODE_ALBUM:
			c = library.getCursor(null, DBConstants.CNAME_ALBUM);
			return new SimpleCursorAdapter(this, R.layout.row, c, new String[] { DBConstants.CNAME_ALBUM }, new int[] { R.id.row });
			
		case MODE_SONG:
			c = library.getCursor(null, DBConstants.CNAME_TITLE);
			return new SimpleCursorAdapter(this, R.layout.row, c, new String[] { DBConstants.CNAME_TITLE }, new int[] { R.id.row });
			
		case MODE_GENRE:
			c = library.getCursor(null, DBConstants.CNAME_GENRE);
			return new SimpleCursorAdapter(this, R.layout.row, c, new String[] { DBConstants.CNAME_GENRE }, new int[] { R.id.row });			
		}
		return null;
	}

	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);		
		
		menu.add(M_GID_MAIN, MITEM_ID_CONFIGURE, MITEM_NAME_CONFIGURE, 
				R.drawable.andro_configure);
		menu.add(M_GID_REGULAR, MITEM_ID_PLAYLIST, MITEM_NAME_PLAYLIST, 
				R.drawable.andro_playlist);
		menu.add(M_GID_REGULAR, MITEM_ID_HELP, MITEM_NAME_HELP, 
				R.drawable.andro_help);
		menu.add(M_GID_REGULAR, MITEM_ID_DONE, MITEM_NAME_DONE, 
				R.drawable.andro_exit);
		menu.add(M_GID_SONG, MITEM_ID_TAGEDITOR, MITEM_NAME_TAGEDITOR, 
				R.drawable.andro_tageditor);
		menu.add(M_GID_MAIN, MITEM_ID_SETPATH, MITEM_NAME_SETPATH,
				R.drawable.andro_setpath);
		
		return true;
	}

	
	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		super.onPrepareOptionsMenu(menu);
		
		if(listMode == MODE_SONG)
			menu.setItemShown(MITEM_ID_TAGEDITOR, true);
		else
			menu.setItemShown(MITEM_ID_TAGEDITOR, false);
		
		if(listMode == MODE_MAIN)
			menu.setGroupShown(M_GID_MAIN, true);
		else
			menu.setGroupShown(M_GID_MAIN, false);
		
		return true;
	}


	@Override
	public boolean onOptionsItemSelected(Item item) {
		super.onOptionsItemSelected(item);
		
		switch(item.getId()) {
		case MITEM_ID_CONFIGURE:
			isConfigured = false;
			
			new Thread(new Runnable() {
				
				private volatile boolean stop = false;
				
				public void run() {
					SharedPreferences sP = ctx.getSharedPreferences(SetPath.SHARED_PREFERENCES_NAME, MODE_PRIVATE);
					String p = sP.getString(SetPath.PREFERENCE_PATH, "");
					File f = new File(p);
					if(!f.exists()) {
						myHandler.post(new Runnable() {
							public void run() {
								showAlert("Error", android.R.id.appIcon, "Illegal Path", "OK", false);
							}
						});
						return;
					}
					
					myHandler.post(new Runnable() {
						public void run() {
							pDialog = ProgressDialog.show(
									ctx,
									"Please Wait",
									"Library Configuration in progress\n" +
									"This Could take a while\n" +
									"(Hit the back button to cancel)",
									true,
									true,
									new OnCancelListener() {
										public void onCancel(DialogInterface dialog) {
											stop = true;
										}
									});
						}
					});
					
					File[] fArr = new File[] { f };
					buildLibrary(fArr);
					if(stop)
						library.clear();
					else {
						myHandler.post(new Runnable() {
							public void run() {
								pDialog.cancel();
							}
						});
						library.setSize();
						isConfigured = true;
					}
					
					try {
						SQLiteDatabase db = openDatabase(DBConstants.DB_NAME, null);
						PlayList playlist = new PlayList(db);
						playlist.clear();
					}
					catch(FileNotFoundException fNFE) {
						myHandler.post(new Runnable() {
							public void run() {
								ctx.showAlert("Error", android.R.id.appIcon, "Unable to clear playlist\nPlaylist maybe out of sync with library", "OK", false);
							}
						});
					}
				}
				
				private void buildLibrary(File[] f) {
					library.clear();
					for(int i=0 ; i<f.length ; i++) {
						if(stop)
							return;
						explore(f[i]);
					}
				}
				
				private void explore(File f) {
					File[] farr = f.listFiles();
					if(farr == null) {
						String fName = f.getName();
						if(stop)
							return;
						if(!(fName.endsWith(".mp3") || fName.endsWith(".MP3")))
							return;
						library.insertMetaData(f);
					}
					else
						for(int i=0 ; i<farr.length ; i++) {
							if(stop)
								return;
							explore(farr[i]);
						}
				}
			}).start();
			break;
			
		case MITEM_ID_PLAYLIST:
			Intent i1 = new Intent(this, PlaylistEditor.class);
			startActivity(i1);
			finish();
			break;
			
		case MITEM_ID_DONE:
			if(addMode)
				setResult(RESULT_OK);
			finish();
			break;
			
		case MITEM_ID_HELP:
			Help.CALLING_ACTIVITY = Help.LIBRARY;
			Intent i2 = new Intent(this, Help.class);
			startActivity(i2);
			break;
			
		case MITEM_ID_TAGEDITOR:
			if(!isConfigured)
				return true;
			try {
				long id = this.getSelectedItemId();
				TagEditor.s = library.getSong(id);
				Intent i = new Intent(this, TagEditor.class);
				startActivity(i);
			}
			catch(IOException e) {
				this.showAlert(PlayScreen.ERROR, android.R.id.icon, "Unable to read song" + "\n" + e.toString(), "OK", false);
				return true;
			}
			break;
			
		case MITEM_ID_SETPATH:
			Intent i = new Intent(this, SetPath.class);
			startSubActivity(i, PlayScreen.SET_PATH);
			break;
		}		
		return true;
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode,
			String data, Bundle extras) {
		super.onActivityResult(requestCode, resultCode, data, extras);
		
		if(requestCode == PlayScreen.SET_PATH)
			if(resultCode == RESULT_OK) {
				library.clear();
				isConfigured = false;			
			}
	}
	
	
}